home *** CD-ROM | disk | FTP | other *** search
/ Programmer Plus 2007 / Programmer-Plus-2007.iso / Programming / XML Utilities / Professional Programmer XSL IDE / Xselerator25.msi / Data.Cab / F28284_datetime_lib.xsl < prev    next >
Encoding:
Extensible Markup Language  |  2002-01-21  |  49.7 KB  |  1,173 lines

  1. <?xml version="1.0"?>
  2. <!--
  3. ==========================================================================
  4.  Stylesheet: datetime_lib.xsl
  5.     Version: 1.1 (2002-01-21)
  6.      Author: Martin "Marrow" Rowlinson
  7.      Notice: (c)2001,2002 MarrowSoft Limited.  ALL RIGHTS RESERVED.
  8.              No limitation on use - except this code may not be published,
  9.              in whole or in part, without prior written consent of copyright
  10.              owner.
  11. ========================================================================== -->
  12. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  13.  
  14. <!-- ========================================================================== -->
  15. <!-- these are 'string arrays' - change for language requirements               -->
  16. <xsl:variable name="default-week-day-names" select="'[1]Monday[2]Tuesday[3]Wednesday[4]Thursday[5]Friday[6]Saturday[7]Sunday[end]'"/>
  17. <xsl:variable name="default-month-names" select="'[01]January[02]February[03]March[04]April[05]May[06]June[07]July[08]August[09]September[10]October[11]November[12]December[end]'"/>
  18. <xsl:variable name="default-am-pm-names" select="'[0]am[1]pm[end]'"/>
  19. <!-- ========================================================================== -->
  20.  
  21. <!--
  22. ==========================================================================
  23.     Template: date-to-julian-day
  24.  Description: Convert a date to julian day
  25.  Parameters:-
  26.     <year> <month> <day>
  27.    or
  28.     <date> (format: yyyymmdd or yyyy-mm-dd)
  29. ========================================================================== -->
  30. <xsl:template name="date-to-julian-day">
  31.     <xsl:param name="year"/>
  32.     <xsl:param name="month"/>
  33.     <xsl:param name="day"/>
  34.     <!-- or -->
  35.     <xsl:param name="date" select="''"/>
  36.     <!-- trim down date -->
  37.     <xsl:variable name="tdate" select="translate($date,'-','')"/>
  38.     <!-- decide which params were passed -->
  39.     <xsl:variable name="yyyy">
  40.         <xsl:choose>
  41.             <xsl:when test="string-length($date) > 0"><xsl:value-of select="substring($tdate,1,4)"/></xsl:when>
  42.             <xsl:otherwise><xsl:value-of select="$year"/></xsl:otherwise>
  43.         </xsl:choose>
  44.     </xsl:variable>
  45.     <xsl:variable name="mm">
  46.         <xsl:choose>
  47.             <xsl:when test="string-length($date) > 0"><xsl:value-of select="substring($tdate,5,2)"/></xsl:when>
  48.             <xsl:otherwise><xsl:value-of select="$month"/></xsl:otherwise>
  49.         </xsl:choose>
  50.     </xsl:variable>
  51.     <xsl:variable name="dd">
  52.         <xsl:choose>
  53.             <xsl:when test="string-length($date) > 0"><xsl:value-of select="substring($tdate,7,2)"/></xsl:when>
  54.             <xsl:otherwise><xsl:value-of select="$day"/></xsl:otherwise>
  55.         </xsl:choose>
  56.     </xsl:variable>
  57.     <!-- pre-calcs -->
  58.     <xsl:variable name="j0" select="ceiling(($mm - 14) div 12)"/>
  59.     <xsl:variable name="j1" select="floor((1461 * ($yyyy + 4800 + $j0)) div 4)"/>
  60.     <xsl:variable name="j2" select="floor((367 * ($mm - 2 - (12 * $j0))) div 12)"/>
  61.     <xsl:variable name="j3" select="floor((3 * floor(($yyyy + 4900 + $j0) div 100)) div 4)"/>
  62.     <!-- final calc -->
  63.     <xsl:value-of select="$j1 + $j2 - $j3 + $dd - 32075"/>
  64. </xsl:template>
  65.  
  66. <!--
  67. ==========================================================================
  68.     Template: julian-day-to-date
  69.  Description: Convert a julian day to date
  70.  Parameters:-
  71.     <julian-day>
  72. ========================================================================== -->
  73. <xsl:template name="julian-day-to-date">
  74.     <xsl:param name="julian-day" select="number(0)"/>
  75.     <!-- pre-calcs -->
  76.     <xsl:variable name="la" select="$julian-day + 68569"/>
  77.     <xsl:variable name="n" select="floor((4 * $la) div 146097)"/>
  78.     <xsl:variable name="lb" select="$la - floor((146097 * $n + 3) div 4)"/>
  79.     <xsl:variable name="i" select="floor((4000 * ($lb + 1)) div 1461001)"/>
  80.     <xsl:variable name="lc" select="$lb - floor((1461 * $i) div 4) + 31"/>
  81.     <xsl:variable name="j" select="floor((80 * $lc) div 2447)"/>
  82.     <xsl:variable name="day" select="$lc - floor((2447 * $j) div 80)"/>
  83.     <xsl:variable name="ld" select="floor($j div 11)"/>
  84.     <xsl:variable name="month" select="$j + 2 - (12 * $ld)"/>
  85.     <xsl:variable name="year" select="100 * ($n - 49) + $i + $ld"/>
  86.     <!-- pad final result -->
  87.     <xsl:variable name="sday" select="concat(substring('00',1,2 - string-length(string($day))),string($day))"/>
  88.     <xsl:variable name="smonth" select="concat(substring('00',1,2 - string-length(string($month))),string($month))"/>
  89.     <xsl:variable name="syear" select="concat(substring('00',1,4 - string-length(string($year))),string($year))"/>
  90.     <!-- final output -->
  91.     <xsl:value-of select="concat($syear,'-',$smonth,'-',$sday)"/>
  92. </xsl:template>
  93.  
  94. <!--
  95. ==========================================================================
  96.     Template: date-diff
  97.  Description: Calculate the difference (in days) between two dates
  98.  Parameters:-
  99.     <year1> <month1> <day1>
  100.    or
  101.     <date1>
  102.  
  103.    and
  104.     <year2> <month2> <day2>
  105.    or
  106.     <date2>
  107. ========================================================================== -->
  108. <xsl:template name="date-diff">
  109.     <xsl:param name="year1"/>
  110.     <xsl:param name="month1"/>
  111.     <xsl:param name="day1"/>
  112.     <xsl:param name="year2"/>
  113.     <xsl:param name="month2"/>
  114.     <xsl:param name="day2"/>
  115.     <!-- or -->
  116.     <xsl:param name="date1" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  117.     <xsl:param name="date2" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  118.     <!-- calc the two julian day numbers -->
  119.     <xsl:variable name="jd1">
  120.         <xsl:call-template name="date-to-julian-day">
  121.             <xsl:with-param name="year" select="$year1"/>
  122.             <xsl:with-param name="month" select="$month1"/>
  123.             <xsl:with-param name="day" select="$day1"/>
  124.             <xsl:with-param name="date" select="$date1"/>
  125.         </xsl:call-template>
  126.     </xsl:variable>
  127.     <xsl:variable name="jd2">
  128.         <xsl:call-template name="date-to-julian-day">
  129.             <xsl:with-param name="year" select="$year2"/>
  130.             <xsl:with-param name="month" select="$month2"/>
  131.             <xsl:with-param name="day" select="$day2"/>
  132.             <xsl:with-param name="date" select="$date2"/>
  133.         </xsl:call-template>
  134.     </xsl:variable>
  135.     <!-- perform calc -->
  136.     <xsl:value-of select="$jd1 - $jd2"/>
  137. </xsl:template>
  138.  
  139. <!--
  140. ==========================================================================
  141.     Template: date-add
  142.  Description: Adds/subtracts a specified number of days to a date
  143.  Parameters:-
  144.     <year> <month> <day>
  145.    or
  146.     <date>
  147.  
  148.    and
  149.     <add> (+ve or -ve)
  150. ========================================================================== -->
  151. <xsl:template name="date-add">
  152.     <xsl:param name="year"/>
  153.     <xsl:param name="month"/>
  154.     <xsl:param name="day"/>
  155.     <!-- or -->
  156.     <xsl:param name="date" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  157.     <!-- and add/subtract days -->
  158.     <xsl:param name="add" select="number(0)"/>
  159.     <!-- get the julian day for the date -->
  160.     <xsl:variable name="jd">
  161.         <xsl:call-template name="date-to-julian-day">
  162.             <xsl:with-param name="year" select="$year"/>
  163.             <xsl:with-param name="month" select="$month"/>
  164.             <xsl:with-param name="day" select="$day"/>
  165.             <xsl:with-param name="date" select="$date"/>
  166.         </xsl:call-template>
  167.     </xsl:variable>
  168.     <!-- add/subtract the modifier to the julian day -->
  169.     <xsl:variable name="output-date">
  170.         <xsl:call-template name="julian-day-to-date">
  171.             <xsl:with-param name="julian-day" select="$jd + $add"/>
  172.         </xsl:call-template>
  173.     </xsl:variable>
  174.     <!-- output resultant -->
  175.     <xsl:value-of select="$output-date"/>
  176. </xsl:template>
  177.  
  178. <!--
  179. ==========================================================================
  180.     Template: date-time-to-float
  181.  Description: Convert a date/time to a floating point.  The date portion is
  182.               returned as the integer part of the number (as julian day)
  183.               and the time portion is represent as fractional of a day.
  184.               (This number is useful for adding times to dates)
  185.  Parameters:-
  186.     <year> <month> <day> <hour> <minute> <second>
  187.    or
  188.     <datetime>
  189. ========================================================================== -->
  190. <xsl:template name="date-time-to-float">
  191.     <xsl:param name="year"/>
  192.     <xsl:param name="month"/>
  193.     <xsl:param name="day"/>
  194.     <xsl:param name="hour"/>
  195.     <xsl:param name="minute"/>
  196.     <xsl:param name="second"/>
  197.     <!-- or -->
  198.     <xsl:param name="datetime" select="''"/>  <!-- format: yyyymmddThhmmss or yyyy-mm-ddThh:mm:ss -->
  199.     <!-- trim down date and pad with midnight -->
  200.     <xsl:variable name="tdatetime" select="concat(translate($datetime,'-T:',''),'000000')"/>
  201.     <!-- decide which params were passed -->
  202.     <xsl:variable name="yyyy">
  203.         <xsl:choose>
  204.             <xsl:when test="string-length($datetime) > 0"><xsl:value-of select="substring($tdatetime,1,4)"/></xsl:when>
  205.             <xsl:otherwise><xsl:value-of select="$year"/></xsl:otherwise>
  206.         </xsl:choose>
  207.     </xsl:variable>
  208.     <xsl:variable name="mm">
  209.         <xsl:choose>
  210.             <xsl:when test="string-length($datetime) > 0"><xsl:value-of select="substring($tdatetime,5,2)"/></xsl:when>
  211.             <xsl:otherwise><xsl:value-of select="$month"/></xsl:otherwise>
  212.         </xsl:choose>
  213.     </xsl:variable>
  214.     <xsl:variable name="dd">
  215.         <xsl:choose>
  216.             <xsl:when test="string-length($datetime) > 0"><xsl:value-of select="substring($tdatetime,7,2)"/></xsl:when>
  217.             <xsl:otherwise><xsl:value-of select="$day"/></xsl:otherwise>
  218.         </xsl:choose>
  219.     </xsl:variable>
  220.     <xsl:variable name="hh">
  221.         <xsl:choose>
  222.             <xsl:when test="string-length($datetime) > 0"><xsl:value-of select="substring($tdatetime,9,2)"/></xsl:when>
  223.             <xsl:otherwise><xsl:value-of select="$hour"/></xsl:otherwise>
  224.         </xsl:choose>
  225.     </xsl:variable>
  226.     <xsl:variable name="nn">
  227.         <xsl:choose>
  228.             <xsl:when test="string-length($datetime) > 0"><xsl:value-of select="substring($tdatetime,11,2)"/></xsl:when>
  229.             <xsl:otherwise><xsl:value-of select="$minute"/></xsl:otherwise>
  230.         </xsl:choose>
  231.     </xsl:variable>
  232.     <xsl:variable name="ss">
  233.         <xsl:choose>
  234.             <xsl:when test="string-length($datetime) > 0"><xsl:value-of select="substring($tdatetime,13,2)"/></xsl:when>
  235.             <xsl:otherwise><xsl:value-of select="$second"/></xsl:otherwise>
  236.         </xsl:choose>
  237.     </xsl:variable>
  238.     <!-- calculate integer part (date) as julian day -->
  239.     <xsl:variable name="jd">
  240.         <xsl:call-template name="date-to-julian-day">
  241.             <xsl:with-param name="year" select="$yyyy"/>
  242.             <xsl:with-param name="month" select="$mm"/>
  243.             <xsl:with-param name="day" select="$dd"/>
  244.         </xsl:call-template>
  245.     </xsl:variable>
  246.     <xsl:value-of select="number($jd) + ($hh * (1 div 24)) + ($nn * (1 div 1440)) + ($ss * (1 div 86400))"/>
  247. </xsl:template>
  248.  
  249. <!--
  250. ==========================================================================
  251.     Template: time-to-float
  252.  Description: Convert a time to a floating point.  The time is returned
  253.               as a fractional part of a day (e.g. 12 noon = 0.5).
  254.               This is useful for adding specified hour differentials
  255.               (such as time zones) to floating point representations of
  256.               date/times.
  257.  Parameters:-
  258.     <hour> <minute> <second>
  259.    or
  260.     <time>
  261. ========================================================================== -->
  262. <xsl:template name="time-to-float">
  263.     <xsl:param name="hour"/>
  264.     <xsl:param name="minute"/>
  265.     <xsl:param name="second"/>
  266.     <!-- or -->
  267.     <xsl:param name="time" select="''"/>  <!-- format: hhmmss or hh:mm:ss -->
  268.     <!-- trim down time by removing ':' chars -->
  269.     <xsl:variable name="ttime" select="translate($time,':','')"/>
  270.     <!-- decide which params were passed -->
  271.     <xsl:variable name="hh">
  272.         <xsl:choose>
  273.             <xsl:when test="string-length($time) > 0"><xsl:value-of select="substring($ttime,1,2)"/></xsl:when>
  274.             <xsl:otherwise><xsl:value-of select="$hour"/></xsl:otherwise>
  275.         </xsl:choose>
  276.     </xsl:variable>
  277.     <xsl:variable name="nn">
  278.         <xsl:choose>
  279.             <xsl:when test="string-length($time) > 0"><xsl:value-of select="concat('0',substring($ttime,3,2))"/></xsl:when>
  280.             <xsl:otherwise><xsl:value-of select="concat('0',$minute)"/></xsl:otherwise>
  281.         </xsl:choose>
  282.     </xsl:variable>
  283.     <xsl:variable name="ss">
  284.         <xsl:choose>
  285.             <xsl:when test="string-length($time) > 0"><xsl:value-of select="concat('0',substring($ttime,5,2))"/></xsl:when>
  286.             <xsl:otherwise><xsl:value-of select="concat('0',$second)"/></xsl:otherwise>
  287.         </xsl:choose>
  288.     </xsl:variable>
  289.     <!-- final resultant -->
  290.     <xsl:value-of select="($hh * (1 div 24)) + ($nn * (1 div 1440)) + ($ss * (1 div 86400))"/>
  291. </xsl:template>
  292.  
  293. <!-- 
  294. ==========================================================================
  295.     Template: float-to-date-time
  296.  Description: Convert a floating point value representing a date/time to
  297.               a date/time string.
  298.  Parameters:-
  299.     <value>  the value to be converted
  300.     <round-seconds>  if true then the seconds are not quoted on the output
  301.                      and, if the seconds are 59 then hour/minute is rounded
  302.                      (this is useful because some processors have limited
  303.                       floating point precision to cope with the seconds)
  304. ========================================================================== -->
  305. <xsl:template name="float-to-date-time">
  306.     <xsl:param name="value" select="number(0)"/>
  307.     <xsl:param name="round-seconds" select="false()"/>
  308.     <xsl:variable name="date">
  309.         <xsl:call-template name="julian-day-to-date">
  310.             <xsl:with-param name="julian-day" select="floor($value)"/>
  311.         </xsl:call-template>
  312.     </xsl:variable>
  313.     <xsl:variable name="t1" select="$value - floor($value)"/>
  314.     <xsl:variable name="h" select="floor($t1 div (1 div 24))"/>
  315.     <xsl:variable name="t2" select="$t1 - ($h * (1 div 24))"/>
  316.     <xsl:variable name="m" select="floor($t2 div (1 div 1440))"/>
  317.     <xsl:variable name="t3" select="$t2 - ($m * (1 div 1440))"/>
  318.     <xsl:choose>
  319.         <xsl:when test="$round-seconds">
  320.             <xsl:variable name="s" select="$t3 div (1 div 86400)"/>
  321.             <xsl:variable name="h2">
  322.                 <xsl:choose>
  323.                     <xsl:when test="($s >= 59) and ($m = 59)"><xsl:value-of select="$h + 1"/></xsl:when>
  324.                     <xsl:otherwise><xsl:value-of select="$h"/></xsl:otherwise>
  325.                 </xsl:choose>
  326.             </xsl:variable>
  327.             <xsl:variable name="m2">
  328.                 <xsl:choose>
  329.                     <xsl:when test="($s >= 59) and ($m = 59)">0</xsl:when>
  330.                     <xsl:when test="($s >= 59)"><xsl:value-of select="$m + 1"/></xsl:when>
  331.                     <xsl:otherwise><xsl:value-of select="$m"/></xsl:otherwise>
  332.                 </xsl:choose>
  333.             </xsl:variable>
  334.             <!-- pad final time result -->
  335.             <xsl:variable name="hh" select="concat(substring('00',1,2 - string-length(string($h2))),string($h2))"/>
  336.             <xsl:variable name="mm" select="concat(substring('00',1,2 - string-length(string($m2))),string($m2))"/>
  337.             <!-- final output resultant -->
  338.             <xsl:value-of select="concat($date,'T',$hh,':',$mm)"/>
  339.         </xsl:when>
  340.         <xsl:otherwise>
  341.             <xsl:variable name="s" select="floor($t3 div (1 div 86400))"/>
  342.             <!-- pad final time result -->
  343.             <xsl:variable name="hh" select="concat(substring('00',1,2 - string-length(string($h))),string($h))"/>
  344.             <xsl:variable name="mm" select="concat(substring('00',1,2 - string-length(string($m))),string($m))"/>
  345.             <xsl:variable name="ss" select="concat(substring('00',1,2 - string-length(string($s))),string($s))"/>
  346.             <!-- final output resultant -->
  347.             <xsl:value-of select="concat($date,'T',$hh,':',$mm,':',$ss)"/>
  348.         </xsl:otherwise>
  349.     </xsl:choose>
  350. </xsl:template>
  351.  
  352. <!--
  353. ==========================================================================
  354.     Template: week-number
  355.  Description: Calculates the week number of a date.
  356.               Week numbers are calculated according to ISO8601 - where week
  357.               number 1 is the week that contains the 4th Jan.
  358.               A week, according to ISO8601, starts on a Monday.
  359.  Parameters:-
  360.     <year> <month> <day>
  361.    or
  362.     <date>
  363.    or
  364.     <julian-day>
  365. ========================================================================== -->
  366. <xsl:template name="week-number">
  367.     <xsl:param name="year"/>
  368.     <xsl:param name="month"/>
  369.     <xsl:param name="day"/>
  370.     <!-- or -->
  371.     <xsl:param name="date" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  372.     <!-- or -->
  373.     <xsl:param name="julian-day" select="''"/>
  374.     <!-- trim down date -->
  375.     <xsl:variable name="tdate" select="translate($date,'-','')"/>
  376.     <!-- decide which params were passed -->
  377.     <xsl:variable name="yyyy">
  378.         <xsl:choose>
  379.             <xsl:when test="string-length($date) > 0"><xsl:value-of select="substring($tdate,1,4)"/></xsl:when>
  380.             <xsl:when test="string-length($julian-day) > 0">
  381.                 <xsl:variable name="jdate">
  382.                     <xsl:call-template name="julian-day-to-date">
  383.                         <xsl:with-param name="julian-day" select="$julian-day"/>
  384.                     </xsl:call-template>
  385.                 </xsl:variable>
  386.                 <xsl:value-of select="substring($jdate,1,4)"/>
  387.             </xsl:when>
  388.             <xsl:otherwise><xsl:value-of select="$year"/></xsl:otherwise>
  389.         </xsl:choose>
  390.     </xsl:variable>
  391.     <!-- get the julian day number -->
  392.     <xsl:variable name="jd">
  393.         <xsl:choose>
  394.             <xsl:when test="string-length($julian-day) > 0"><xsl:value-of select="$julian-day"/></xsl:when>
  395.             <xsl:otherwise>
  396.                 <xsl:call-template name="date-to-julian-day">
  397.                     <xsl:with-param name="year" select="$year"/>
  398.                     <xsl:with-param name="month" select="$month"/>
  399.                     <xsl:with-param name="day" select="$day"/>
  400.                     <xsl:with-param name="date" select="$date"/>
  401.                 </xsl:call-template>
  402.             </xsl:otherwise>
  403.         </xsl:choose>
  404.     </xsl:variable>
  405.     <!-- get the julian day number for the first working day of next year -->
  406.     <xsl:variable name="fyjd">
  407.         <xsl:call-template name="first-day-of-year">
  408.             <xsl:with-param name="year" select="$yyyy+1"/>
  409.             <xsl:with-param name="as-julian-day" select="true()"/>
  410.         </xsl:call-template>
  411.     </xsl:variable>
  412.     <!-- decide which the 'working' year for this date is -->
  413.     <xsl:variable name="start-jd">
  414.         <xsl:choose>
  415.             <xsl:when test="$jd >= $fyjd"><xsl:value-of select="$fyjd"/></xsl:when>
  416.             <xsl:otherwise>
  417.                 <xsl:call-template name="date-to-julian-day">
  418.                     <xsl:with-param name="date">
  419.                         <xsl:call-template name="first-day-of-year">
  420.                             <xsl:with-param name="year" select="$yyyy"/>
  421.                         </xsl:call-template>
  422.                     </xsl:with-param>
  423.                 </xsl:call-template>
  424.             </xsl:otherwise>
  425.         </xsl:choose>
  426.     </xsl:variable>
  427.     <!-- final calc output -->
  428.     <xsl:value-of select="floor(($jd - $start-jd) div 7) + 1"/>
  429. </xsl:template>
  430.  
  431. <!--
  432. ==========================================================================
  433.     Template: week-number-to-date
  434.  Description: Calculates the date of the Monday of the given week number in
  435.               the specified year.
  436.               Week numbers are calculated according to ISO8601 - where week
  437.               number 1 is the week that contains the 4th Jan.
  438.               A week, according to ISO8601, starts on a Monday.
  439.  Parameters:-
  440.     <week> <year>
  441.     [<as-julian-day>]
  442. ========================================================================== -->
  443. <xsl:template name="week-number-to-date">
  444.     <xsl:param name="week" select="number(1)"/>
  445.     <xsl:param name="year" select="number(1)"/>
  446.     <!-- return date as julian day -->
  447.     <xsl:param name="as-julian-day" select="false()"/>
  448.     <!-- calc first working day of year -->
  449.     <xsl:variable name="fwdy">
  450.         <xsl:call-template name="first-day-of-year">
  451.             <xsl:with-param name="year" select="$year"/>
  452.             <xsl:with-param name="as-julian-day" select="true()"/>
  453.         </xsl:call-template>
  454.     </xsl:variable>
  455.     <xsl:variable name="wntd" select="$fwdy + (($week - 1) * 7)"/>
  456.     <xsl:choose>
  457.         <xsl:when test="$as-julian-day"><xsl:value-of select="$wntd"/></xsl:when>
  458.         <xsl:otherwise>
  459.             <xsl:call-template name="julian-day-to-date">
  460.                 <xsl:with-param name="julian-day" select="$wntd"/>
  461.             </xsl:call-template>
  462.         </xsl:otherwise>
  463.     </xsl:choose>
  464. </xsl:template>
  465.  
  466. <!--
  467. ==========================================================================
  468.     Template: working-year
  469.  Description: Calculates the working year of a given date.
  470.               A date may actually appear as a working day of the previous
  471.               year - as specified by the week calculations according to
  472.               ISO8601 (where week number 1 begins the week containing the
  473.               4th Jan).
  474.  Parameters:-
  475.     <year> <month> <day>
  476.    or
  477.     <date>
  478.    or
  479.     <julian-day>
  480. ========================================================================== -->
  481. <xsl:template name="working-year">
  482.     <xsl:param name="year"/>
  483.     <xsl:param name="month"/>
  484.     <xsl:param name="day"/>
  485.     <!-- or -->
  486.     <xsl:param name="date" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  487.     <!-- or -->
  488.     <xsl:param name="julian-day" select="''"/>
  489.     <!-- trim down date -->
  490.     <xsl:variable name="tdate" select="translate($date,'-','')"/>
  491.     <!-- decide which params were passed -->
  492.     <xsl:variable name="yyyy">
  493.         <xsl:choose>
  494.             <xsl:when test="string-length($date) > 0"><xsl:value-of select="substring($tdate,1,4)"/></xsl:when>
  495.             <xsl:when test="string-length($julian-day) > 0">
  496.                 <xsl:variable name="jdate">
  497.                     <xsl:call-template name="julian-day-to-date">
  498.                         <xsl:with-param name="julian-day" select="$julian-day"/>
  499.                     </xsl:call-template>
  500.                 </xsl:variable>
  501.                 <xsl:value-of select="substring($jdate,1,4)"/>
  502.             </xsl:when>
  503.             <xsl:otherwise><xsl:value-of select="$year"/></xsl:otherwise>
  504.         </xsl:choose>
  505.     </xsl:variable>
  506.     <!-- get the julian day number -->
  507.     <xsl:variable name="jd">
  508.         <xsl:choose>
  509.             <xsl:when test="string-length($julian-day) > 0"><xsl:value-of select="$julian-day"/></xsl:when>
  510.             <xsl:otherwise>
  511.                 <xsl:call-template name="date-to-julian-day">
  512.                     <xsl:with-param name="year" select="$year"/>
  513.                     <xsl:with-param name="month" select="$month"/>
  514.                     <xsl:with-param name="day" select="$day"/>
  515.                     <xsl:with-param name="date" select="$date"/>
  516.                 </xsl:call-template>
  517.             </xsl:otherwise>
  518.         </xsl:choose>
  519.     </xsl:variable>
  520.     <!-- get the julian day number for the first working day of next year -->
  521.     <xsl:variable name="fyjd">
  522.         <xsl:call-template name="first-day-of-year">
  523.             <xsl:with-param name="year" select="$yyyy+1"/>
  524.             <xsl:with-param name="as-julian-day" select="true()"/>
  525.         </xsl:call-template>
  526.     </xsl:variable>
  527.     <!-- decide which the 'working' year for this date is -->
  528.     <xsl:choose>
  529.         <xsl:when test="$jd >= $fyjd"><xsl:value-of select="$yyyy+1"/></xsl:when>
  530.         <xsl:otherwise><xsl:value-of select="$yyyy"/></xsl:otherwise>
  531.     </xsl:choose>
  532. </xsl:template>
  533.  
  534. <!--
  535. ==========================================================================
  536.     Template: weeks-in-year
  537.  Description: Calculates the number of weeks in a year according to the
  538.               ISO8601 standard for weeks.
  539.  Parameters:-
  540.     <year>
  541. ========================================================================== -->
  542. <xsl:template name="weeks-in-year">
  543.     <xsl:param name="year" select="number(0)"/>
  544.     <xsl:variable name="syear" select="concat(substring('0000',1,4 - string-length($year)),$year)"/>
  545.     <!-- last week in year is always the week that contains 28th December -->
  546.     <xsl:call-template name="week-number">
  547.         <xsl:with-param name="date" select="concat($syear,'1228')"/>
  548.     </xsl:call-template>
  549. </xsl:template>
  550.  
  551. <!--
  552. ==========================================================================
  553.     Template: first-day-of-year
  554.  Description: Calculates the first working day of the year (Monday)
  555.               according to ISO8601 where week 1 of a year is the week that
  556.               contains the 4th Jan.
  557.  Parameters:-
  558.     <year>
  559.     [<as-julian-day>]
  560. ========================================================================== -->
  561. <xsl:template name="first-day-of-year">
  562.     <xsl:param name="year"/>
  563.     <xsl:param name="as-julian-day" select="false()"/>
  564.     <xsl:variable name="syear" select="concat(substring('0000',1,4 - string-length($year)),$year)"/>
  565.     <!-- week 1 is the week containing 4th Jan -->
  566.     <xsl:variable name="jan4-jd">
  567.         <xsl:call-template name="date-to-julian-day">
  568.             <xsl:with-param name="date" select="concat($syear,'0104')"/>
  569.         </xsl:call-template>
  570.     </xsl:variable>
  571.     <!-- get the week day for the 4th Jan -->
  572.     <xsl:variable name="jan4-wd">
  573.         <xsl:call-template name="day-of-week">
  574.             <xsl:with-param name="date" select="concat($syear,'0104')"/>
  575.         </xsl:call-template>
  576.     </xsl:variable>
  577.     <!-- first day is the prev monday -->
  578.     <xsl:choose>
  579.         <xsl:when test="$as-julian-day"><xsl:value-of select="$jan4-jd - ($jan4-wd - 1)"/></xsl:when>
  580.         <xsl:otherwise>
  581.             <xsl:call-template name="julian-day-to-date">
  582.                 <xsl:with-param name="julian-day" select="$jan4-jd - ($jan4-wd - 1)"/>
  583.             </xsl:call-template>
  584.         </xsl:otherwise>
  585.     </xsl:choose>
  586. </xsl:template>
  587.  
  588. <!--
  589. ==========================================================================
  590.     Template: day-of-week
  591.  Description: Calculates the day of the week for a date - where the first
  592.               day of the week is Monday (1) and the last day of the week is
  593.               is Sunday (7) - according to ISO8601.
  594.  Parameters:-
  595.     <year> <month> <day>
  596.    or
  597.     <date>
  598.    or
  599.     <julian-day>
  600. ========================================================================== -->
  601. <xsl:template name="day-of-week">
  602.     <xsl:param name="year"/>
  603.     <xsl:param name="month"/>
  604.     <xsl:param name="day"/>
  605.     <!-- or -->
  606.     <xsl:param name="date" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  607.     <!-- or -->
  608.     <xsl:param name="julian-day" select="''"/>
  609.     <!-- get julian day -->
  610.     <xsl:variable name="jd">
  611.         <xsl:choose>
  612.             <xsl:when test="string-length($julian-day) > 0"><xsl:value-of select="$julian-day"/></xsl:when>
  613.             <xsl:otherwise>
  614.                 <xsl:call-template name="date-to-julian-day">
  615.                     <xsl:with-param name="year" select="$year"/>
  616.                     <xsl:with-param name="month" select="$month"/>
  617.                     <xsl:with-param name="day" select="$day"/>
  618.                     <xsl:with-param name="date" select="$date"/>
  619.                 </xsl:call-template>
  620.             </xsl:otherwise>
  621.         </xsl:choose>
  622.     </xsl:variable>
  623.     <!-- pre-calcs -->
  624.     <xsl:variable name="dw0" select="$jd mod 10227"/>
  625.     <xsl:value-of select="($dw0 mod 7) + 1"/>
  626. </xsl:template>
  627.  
  628. <!--
  629. ==========================================================================
  630.     Template: named-day-of-week
  631.  Description: Calculates the day of the week for a date - where the first
  632.               day of the week is Monday (1) and the last day of the week is
  633.               is Sunday (7) - according to ISO8601.
  634.               The day of week is returned as its name.
  635.  Parameters:-
  636.     <year> <month> <day>
  637.    or
  638.     <date>
  639.    or
  640.     <julian-day>
  641.    optional override parameter:-
  642.    [<week-day-names>]
  643. ========================================================================== -->
  644. <xsl:template name="named-day-of-week">
  645.     <xsl:param name="year"/>
  646.     <xsl:param name="month"/>
  647.     <xsl:param name="day"/>
  648.     <!-- or -->
  649.     <xsl:param name="date" select="''"/>  <!-- format: yyyymmdd or yyyy-mm-dd -->
  650.     <!-- or -->
  651.     <xsl:param name="julian-day" select="''"/>
  652.     <!-- override week day names parameter -->
  653.     <xsl:param name="week-day-names" select="$default-week-day-names"/>
  654.     <!-- get numeric day of week -->
  655.     <xsl:variable name="dwn">
  656.         <xsl:text>[</xsl:text>
  657.         <xsl:call-template name="day-of-week">
  658.             <xsl:with-param name="year" select="$year"/>
  659.             <xsl:with-param name="month" select="$month"/>
  660.             <xsl:with-param name="day" select="$day"/>
  661.             <xsl:with-param name="date" select="$date"/>
  662.             <xsl:with-param name="julian-day" select="$julian-day"/>
  663.         </xsl:call-template>
  664.         <xsl:text>]</xsl:text>
  665.     </xsl:variable>
  666.     <xsl:value-of select="substring-before(substring($week-day-names,string-length(substring-before($week-day-names,$dwn)) + 4),'[')"/>
  667. </xsl:template>
  668.  
  669. <!--
  670. ==========================================================================
  671.     Template: format-date-time
  672.  Description: Formats a given date/time according to a format string.
  673.  Parameters:-
  674.    <format-string>
  675.  
  676.     <year> <month> <day> <hour> <minute> <second>
  677.    or
  678.     <datetime>
  679.    or
  680.     <julian-day>
  681.    optional override parameters:-
  682.    [<week-day-names>]
  683.    [<month-names>]
  684.    [<am-pm-names>]
  685.  
  686.  Format string tokens:-
  687.    yyyy    : Year (4-digit)
  688.    yy      : Year (2-digit)
  689.    mmmm    : Month name (full)
  690.    mmm     : Month name (abbreviated to 3 chars)
  691.    mm      : Month (padded with zero to two digits)
  692.    m       : Month (1 ro 2 digits)
  693.    dd      : Day (padded with zero to teo digits)
  694.    d       : Day (1 or 2 digits)
  695.    th      : nth day modifier (e.g. st, nd, rd, th)
  696.    dowwww  : Day of week (full - e.g Monday, Tuesday etc.)
  697.    dowww   : Day of week (abbreviated to 3 chars - e.g. Mon, Tue etc.)
  698.    dow     : Day of week (numeric: 1=Monday)
  699.    wyyyy   : Working year (4-digit)
  700.    wyy     : Working year (2-digit)
  701.    wnn     : Week number (padded with zero to two digits)
  702.    wn      : Week number (1 or 2 digits)
  703.    hm      : Hour (reduced to 12-hour clock - 1 or 2 digits)
  704.    hh      : Hour (24-hour clock - padded with zero to two digits)
  705.    h       : Hour (1 or 2 digits)
  706.    nn      : Minute (padded with zero to two digits)
  707.    n       : Minute (1 or 2 digits)
  708.    ss      : Second (padded with zero to two digits)
  709.    s       : Second (1 or 2 digits)
  710.    apm     : am/pm marker
  711.    'x...x' : Literal string
  712.    "x...x" : Literal string
  713. ========================================================================== -->
  714. <xsl:template name="format-date-time">
  715.     <!-- required format -->
  716.     <xsl:param name="format-string">yyyy-mm-dd'T'hh:nn:ss</xsl:param>
  717.     <!-- passed date/time -->
  718.     <xsl:param name="year"/>
  719.     <xsl:param name="month"/>
  720.     <xsl:param name="day"/>
  721.     <xsl:param name="hour"/>
  722.     <xsl:param name="minute"/>
  723.     <xsl:param name="second"/>
  724.     <!-- or -->
  725.     <xsl:param name="datetime" select="''"/>  <!-- format: yyyymmddThhmmss or yyyy-mm-ddThh:mm:ss -->
  726.     <!-- or -->
  727.     <xsl:param name="julian-day" select="''"/> <!-- this can be float type to include times -->
  728.     <!-- default week day, month and am/pm names overrides -->
  729.     <xsl:param name="week-day-names" select="$default-week-day-names"/>
  730.     <xsl:param name="month-names" select="$default-month-names"/>
  731.     <xsl:param name="am-pm-names" select="$default-am-pm-names"/>
  732.     <!-- convert date passed to common format -->
  733.     <xsl:variable name="use-datetime">
  734.         <xsl:choose>
  735.             <xsl:when test="string-length($datetime) > 0">
  736.                 <xsl:variable name="tdate" select="translate($datetime,'-:T','')"/>
  737.                 <xsl:value-of select="concat($tdate,substring('00000000000000',1,14 - string-length($tdate)))"/>
  738.             </xsl:when>
  739.             <xsl:when test="string-length($julian-day) > 0">
  740.                 <xsl:variable name="tdate">
  741.                     <xsl:call-template name="float-to-date-time">
  742.                         <xsl:with-param name="value" select="$julian-day"/>
  743.                     </xsl:call-template>
  744.                 </xsl:variable>
  745.                 <xsl:value-of select="translate($tdate,'-:T','')"/>
  746.             </xsl:when>
  747.             <xsl:otherwise>
  748.                 <xsl:value-of select="concat(substring('0000',1,4 - string-length($year)),$year)"/>
  749.                 <xsl:value-of select="concat(substring('00',1,2 - string-length($month)),$month)"/>
  750.                 <xsl:value-of select="concat(substring('00',1,2 - string-length($day)),$day)"/>
  751.                 <xsl:value-of select="concat(substring('00',1,2 - string-length($hour)),$hour)"/>
  752.                 <xsl:value-of select="concat(substring('00',1,2 - string-length($minute)),$minute)"/>
  753.                 <xsl:value-of select="concat(substring('00',1,2 - string-length($second)),$second)"/>
  754.             </xsl:otherwise>
  755.         </xsl:choose>
  756.     </xsl:variable>
  757.     <xsl:call-template name="format-date-time-tokenizer">
  758.         <xsl:with-param name="fmt" select="$format-string"/>
  759.         <xsl:with-param name="datetime" select="$use-datetime"/>
  760.         <xsl:with-param name="week-day-names" select="$week-day-names"/>
  761.         <xsl:with-param name="month-names" select="$month-names"/>
  762.         <xsl:with-param name="am-pm-names" select="$am-pm-names"/>
  763.     </xsl:call-template>
  764. </xsl:template>
  765. <xsl:template name="format-date-time-tokenizer">
  766.     <xsl:param name="fmt">yyyy-mm-dd'T'hh:nn:ss</xsl:param>
  767.     <xsl:param name="datetime"/>
  768.     <xsl:param name="week-day-names" select="$default-week-day-names"/>
  769.     <xsl:param name="month-names" select="$default-month-names"/>
  770.     <xsl:param name="am-pm-names" select="$default-am-pm-names"/>
  771.     <xsl:if test="string-length($fmt) > 0">
  772.         <xsl:variable name="token">
  773.             <xsl:choose>
  774.                 <xsl:when test="substring($fmt,1,4) = 'yyyy'"><xsl:text>yyyy</xsl:text></xsl:when>
  775.                 <xsl:when test="substring($fmt,1,2) = 'yy'"><xsl:text>yy</xsl:text></xsl:when>
  776.                 <xsl:when test="substring($fmt,1,4) = 'mmmm'"><xsl:text>mmmm</xsl:text></xsl:when>
  777.                 <xsl:when test="substring($fmt,1,3) = 'mmm'"><xsl:text>mmm</xsl:text></xsl:when>
  778.                 <xsl:when test="substring($fmt,1,2) = 'mm'"><xsl:text>mm</xsl:text></xsl:when>
  779.                 <xsl:when test="substring($fmt,1,1) = 'm'"><xsl:text>m</xsl:text></xsl:when>
  780.                 <xsl:when test="substring($fmt,1,2) = 'th'"><xsl:text>th</xsl:text></xsl:when>
  781.                 <xsl:when test="substring($fmt,1,6) = 'dowwww'"><xsl:text>dowwww</xsl:text></xsl:when>
  782.                 <xsl:when test="substring($fmt,1,5) = 'dowww'"><xsl:text>dowww</xsl:text></xsl:when>
  783.                 <xsl:when test="substring($fmt,1,3) = 'dow'"><xsl:text>dow</xsl:text></xsl:when>
  784.                 <xsl:when test="substring($fmt,1,2) = 'dd'"><xsl:text>dd</xsl:text></xsl:when>
  785.                 <xsl:when test="substring($fmt,1,1) = 'd'"><xsl:text>d</xsl:text></xsl:when>
  786.                 <xsl:when test="substring($fmt,1,5) = 'wyyyy'"><xsl:text>wyyyy</xsl:text></xsl:when>
  787.                 <xsl:when test="substring($fmt,1,3) = 'wyy'"><xsl:text>wyy</xsl:text></xsl:when>
  788.                 <xsl:when test="substring($fmt,1,3) = 'wnn'"><xsl:text>wnn</xsl:text></xsl:when>
  789.                 <xsl:when test="substring($fmt,1,2) = 'wn'"><xsl:text>wn</xsl:text></xsl:when>
  790.                 <xsl:when test="substring($fmt,1,2) = 'hm'"><xsl:text>hm</xsl:text></xsl:when>
  791.                 <xsl:when test="substring($fmt,1,2) = 'hh'"><xsl:text>hh</xsl:text></xsl:when>
  792.                 <xsl:when test="substring($fmt,1,1) = 'h'"><xsl:text>h</xsl:text></xsl:when>
  793.                 <xsl:when test="substring($fmt,1,2) = 'nn'"><xsl:text>nn</xsl:text></xsl:when>
  794.                 <xsl:when test="substring($fmt,1,1) = 'n'"><xsl:text>n</xsl:text></xsl:when>
  795.                 <xsl:when test="substring($fmt,1,2) = 'ss'"><xsl:text>ss</xsl:text></xsl:when>
  796.                 <xsl:when test="substring($fmt,1,1) = 's'"><xsl:text>s</xsl:text></xsl:when>
  797.                 <xsl:when test="substring($fmt,1,3) = 'apm'"><xsl:text>apm</xsl:text></xsl:when>
  798.                 <xsl:when test='string-length(translate(substring($fmt,1,1),"'","")) = 0'>
  799.                     <xsl:variable name="rn" select='string-length(substring-before(substring($fmt,2),"'"))'/>
  800.                     <xsl:value-of select="substring($fmt,1,$rn+2)"/>
  801.                 </xsl:when>
  802.                 <xsl:when test="string-length(translate(substring($fmt,1,1),'"','')) = 0">
  803.                     <xsl:variable name="rn" select="string-length(substring-before(substring($fmt,2),'"'))"/>
  804.                     <xsl:value-of select="substring($fmt,1,$rn+2)"/>
  805.                 </xsl:when>
  806.                 <xsl:otherwise><xsl:value-of select="substring($fmt,1,1)"/></xsl:otherwise>
  807.             </xsl:choose>        
  808.         </xsl:variable>
  809.         <!-- handle the token -->
  810.         <xsl:call-template name="format-date-time-tokens">
  811.             <xsl:with-param name="token" select="$token"/>
  812.             <xsl:with-param name="datetime" select="$datetime"/>
  813.             <xsl:with-param name="week-day-names" select="$week-day-names"/>
  814.             <xsl:with-param name="month-names" select="$month-names"/>
  815.             <xsl:with-param name="am-pm-names" select="$am-pm-names"/>
  816.         </xsl:call-template>
  817.         <!-- recurse into self to handle rest of format string -->
  818.         <xsl:call-template name="format-date-time-tokenizer">
  819.             <xsl:with-param name="fmt" select="substring($fmt,string-length($token) + 1)"/>
  820.             <xsl:with-param name="datetime" select="$datetime"/>
  821.             <xsl:with-param name="week-day-names" select="$week-day-names"/>
  822.             <xsl:with-param name="month-names" select="$month-names"/>
  823.             <xsl:with-param name="am-pm-names" select="$am-pm-names"/>
  824.         </xsl:call-template>
  825.     </xsl:if>
  826. </xsl:template>
  827. <xsl:template name="format-date-time-tokens">
  828.     <xsl:param name="token"/>
  829.     <xsl:param name="datetime"/>
  830.     <xsl:param name="week-day-names"/>
  831.     <xsl:param name="month-names"/>
  832.     <xsl:param name="am-pm-names"/>
  833.     <xsl:choose>
  834.         <xsl:when test="$token = 'yyyy'">
  835.             <xsl:value-of select="substring($datetime,1,4)"/>
  836.         </xsl:when>
  837.         <xsl:when test="$token = 'yy'">
  838.             <xsl:value-of select="substring($datetime,3,2)"/>
  839.         </xsl:when>
  840.         <xsl:when test="$token = 'mmmm'">
  841.             <xsl:variable name="mn" select="concat('[',substring($datetime,5,2),']')"/>
  842.             <xsl:value-of select="substring-before(substring($month-names,string-length(substring-before($month-names,$mn)) + 5),'[')"/>
  843.         </xsl:when>
  844.         <xsl:when test="$token = 'mmm'">
  845.             <xsl:variable name="mn" select="concat('[',substring($datetime,5,2),']')"/>
  846.             <xsl:value-of select="substring(substring-before(substring($month-names,string-length(substring-before($month-names,$mn)) + 5),'['),1,3)"/>
  847.         </xsl:when>
  848.         <xsl:when test="$token = 'mm'">
  849.             <xsl:value-of select="substring($datetime,5,2)"/>
  850.         </xsl:when>
  851.         <xsl:when test="$token = 'm'">
  852.             <xsl:value-of select="number(substring($datetime,5,2))"/>
  853.         </xsl:when>
  854.         <xsl:when test="$token = 'th'">
  855.             <xsl:choose>
  856.                 <xsl:when test="substring($datetime,8,1) = '0' or substring($datetime,7,1) = '1'"><xsl:text>th</xsl:text></xsl:when>
  857.                 <xsl:otherwise>
  858.                     <xsl:choose>
  859.                         <xsl:when test="substring($datetime,8,1) = '1'"><xsl:text>st</xsl:text></xsl:when>
  860.                         <xsl:when test="substring($datetime,8,1) = '2'"><xsl:text>nd</xsl:text></xsl:when>
  861.                         <xsl:when test="substring($datetime,8,1) = '3'"><xsl:text>rd</xsl:text></xsl:when>
  862.                         <xsl:otherwise><xsl:text>th</xsl:text></xsl:otherwise>
  863.                     </xsl:choose>
  864.                 </xsl:otherwise>
  865.             </xsl:choose>
  866.         </xsl:when>
  867.         <xsl:when test="$token = 'dd'">
  868.             <xsl:value-of select="substring($datetime,7,2)"/>
  869.         </xsl:when>
  870.         <xsl:when test="$token = 'd'">
  871.             <xsl:value-of select="number(substring($datetime,7,2))"/>
  872.         </xsl:when>
  873.         <xsl:when test="$token = 'dowwww'">
  874.             <xsl:call-template name="named-day-of-week">
  875.                 <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  876.                 <xsl:with-param name="week-day-names" select="$week-day-names"/>
  877.             </xsl:call-template>
  878.         </xsl:when>
  879.         <xsl:when test="$token = 'dowww'">
  880.             <xsl:variable name="dow">
  881.                 <xsl:call-template name="named-day-of-week">
  882.                     <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  883.                     <xsl:with-param name="week-day-names" select="$week-day-names"/>
  884.                 </xsl:call-template>
  885.             </xsl:variable>
  886.             <xsl:value-of select="substring($dow,1,3)"/>
  887.         </xsl:when>
  888.         <xsl:when test="$token = 'dow'">
  889.             <xsl:call-template name="day-of-week">
  890.                 <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  891.             </xsl:call-template>
  892.         </xsl:when>
  893.         <xsl:when test="$token = 'wyyyy'">
  894.             <xsl:call-template name="working-year">
  895.                 <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  896.             </xsl:call-template>
  897.         </xsl:when>
  898.         <xsl:when test="$token = 'wyy'">
  899.             <xsl:variable name="wyy">
  900.                 <xsl:call-template name="working-year">
  901.                     <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  902.                 </xsl:call-template>
  903.             </xsl:variable>
  904.             <xsl:value-of select="substring($wyy,3,2)"/>
  905.         </xsl:when>
  906.         <xsl:when test="$token = 'wnn'">
  907.             <xsl:variable name="wn">
  908.                 <xsl:call-template name="week-number">
  909.                     <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  910.                 </xsl:call-template>
  911.             </xsl:variable>
  912.             <xsl:value-of select="concat(substring('00',1,2 - string-length($wn)),$wn)"/>
  913.         </xsl:when>
  914.         <xsl:when test="$token = 'wn'">
  915.             <xsl:call-template name="week-number">
  916.                 <xsl:with-param name="date" select="substring($datetime,1,8)"/>
  917.             </xsl:call-template>
  918.         </xsl:when>
  919.         <xsl:when test="$token = 'hm'">
  920.             <xsl:variable name="hm" select="number(substring($datetime,9,2))"/>
  921.             <xsl:choose>
  922.                 <xsl:when test="$hm > 12"><xsl:value-of select="$hm - 12"/></xsl:when>
  923.                 <xsl:otherwise><xsl:value-of select="$hm"/></xsl:otherwise>
  924.             </xsl:choose>
  925.         </xsl:when>
  926.         <xsl:when test="$token = 'hh'">
  927.             <xsl:value-of select="substring($datetime,9,2)"/>
  928.         </xsl:when>
  929.         <xsl:when test="$token = 'h'">
  930.             <xsl:value-of select="number(substring($datetime,9,2))"/>
  931.         </xsl:when>
  932.         <xsl:when test="$token = 'nn'">
  933.             <xsl:value-of select="substring($datetime,11,2)"/>
  934.         </xsl:when>
  935.         <xsl:when test="$token = 'n'">
  936.             <xsl:value-of select="number(substring($datetime,11,2))"/>
  937.         </xsl:when>
  938.         <xsl:when test="$token = 'ss'">
  939.             <xsl:value-of select="substring($datetime,13,2)"/>
  940.         </xsl:when>
  941.         <xsl:when test="$token = 's'">
  942.             <xsl:value-of select="number(substring($datetime,13,2))"/>
  943.         </xsl:when>
  944.         <xsl:when test="$token = 'apm'">
  945.             <xsl:variable name="apm" select="concat('[',number(substring($datetime,9,2)) mod 12,']')"/>
  946.             <xsl:value-of select="substring-before(substring($am-pm-names,string-length(substring-before($am-pm-names,$apm)) + 4),'[')"/>
  947.         </xsl:when>
  948.         <xsl:when test='string-length(translate(substring($token,1,1),"'","")) = 0'>
  949.             <xsl:value-of select="substring($token,2,string-length($token) - 2)"/>
  950.         </xsl:when>
  951.         <xsl:when test="string-length(translate(substring($token,1,1),'"','')) = 0">
  952.             <xsl:value-of select="substring($token,2,string-length($token) - 2)"/>
  953.         </xsl:when>
  954.         <xsl:otherwise><xsl:value-of select="$token"/></xsl:otherwise>
  955.     </xsl:choose>
  956. </xsl:template>
  957.  
  958. <!--
  959. ==========================================================================
  960.     Template: local-to-UTC
  961.  Description: Converts a local date/time (in the format yyyymmddThhmmssZ+-hhmm
  962.               or yyyy-mm-ddThh:mm:ssZ+-hh:mm) to a UTC date/time.
  963.  Parameters:-
  964.    <datetime> the local date/time to be converted.
  965. -->
  966. <xsl:template name="local-to-UTC">
  967.     <xsl:param name="datetime"/>
  968.     <!-- get the time zone offset part of the date/time -->
  969.     <xsl:variable name="local-offset">
  970.         <xsl:choose>
  971.             <xsl:when test="contains($datetime,'Z')">
  972.                 <!-- get the local offset portion (and strip out '+' and ':' chars) -->
  973.                 <xsl:variable name="offset-portion" select="translate(substring-after($datetime,'Z'),'+:','')"/>
  974.                 <xsl:choose>
  975.                     <xsl:when test="string-length($offset-portion) = 0">0</xsl:when>
  976.                     <xsl:otherwise>
  977.                         <!-- convert hours/mins to a numeric value -->
  978.                         <xsl:variable name="offset-val">
  979.                             <xsl:call-template name="time-to-float">
  980.                                 <xsl:with-param name="time" select="translate($offset-portion,'-','')"/>
  981.                             </xsl:call-template>
  982.                         </xsl:variable>
  983.                         <!-- adjust value + or - -->
  984.                         <xsl:choose>
  985.                             <xsl:when test="substring($offset-portion,1,1) = '-'"><xsl:value-of select="$offset-val"/></xsl:when>
  986.                             <xsl:otherwise><xsl:value-of select="0 - $offset-val"/></xsl:otherwise>
  987.                         </xsl:choose>
  988.                     </xsl:otherwise>
  989.                 </xsl:choose>
  990.             </xsl:when>
  991.             <xsl:otherwise>0</xsl:otherwise>
  992.         </xsl:choose>
  993.     </xsl:variable>
  994.     <xsl:choose>
  995.         <xsl:when test="$local-offset != 0">
  996.             <xsl:variable name="dt2" select="translate(substring-before($datetime,'Z'),'-T:','')"/>
  997.             <xsl:variable name="date-value">
  998.                 <xsl:call-template name="date-time-to-float">
  999.                     <xsl:with-param name="datetime" select="$dt2"/>
  1000.                 </xsl:call-template>
  1001.             </xsl:variable>
  1002.             <xsl:variable name="output-datetime">
  1003.                 <xsl:call-template name="float-to-date-time">
  1004.                     <xsl:with-param name="value" select="$date-value + $local-offset"/>
  1005.                     <xsl:with-param name="round-seconds" select="true()"/>
  1006.                 </xsl:call-template>
  1007.             </xsl:variable>
  1008.             <!-- if seconds specified on the original time then add these back on -->
  1009.             <xsl:choose>
  1010.                 <xsl:when test="string-length($dt2) > 12"><xsl:value-of select="concat($output-datetime,':',substring($dt2,13,2))"/></xsl:when>
  1011.                 <xsl:otherwise><xsl:value-of select="$output-datetime"/></xsl:otherwise>
  1012.             </xsl:choose>
  1013.         </xsl:when>
  1014.         <xsl:otherwise><xsl:value-of select="concat($datetime,'Z')"/></xsl:otherwise>
  1015.     </xsl:choose>
  1016. </xsl:template>
  1017.  
  1018. <!--
  1019. ==========================================================================
  1020.     Template: UTC-to-local
  1021.  Description: Converts a UTC date/time (in the format yyyymmddThhmmss
  1022.               or yyyy-mm-ddThh:mm:ss) to a local date/time.
  1023.  Parameters:-
  1024.    <datetime>     the UTC date/time to be converted.
  1025.    <local-offset> the local time offset (in the format +hh:mm or
  1026.                   -hh:mm)
  1027. -->
  1028. <xsl:template name="UTC-to-local">
  1029.     <xsl:param name="datetime"/>
  1030.     <xsl:param name="local-offset" select="'0000'"/>
  1031.     <xsl:variable name="raw-offset" select="concat(substring('0000',1,4 - string-length(translate($local-offset,'+-:',''))),translate($local-offset,'+-:',''))"/>
  1032.     <!-- calc the offset as a value -->
  1033.     <xsl:variable name="offset">
  1034.         <xsl:choose>
  1035.             <xsl:when test="$raw-offset = '0000'">0</xsl:when>
  1036.             <xsl:otherwise>
  1037.                 <!-- convert hours/mins to a numeric value -->
  1038.                 <xsl:variable name="offset-val">
  1039.                     <xsl:call-template name="time-to-float">
  1040.                         <xsl:with-param name="time" select="$raw-offset"/>
  1041.                     </xsl:call-template>
  1042.                 </xsl:variable>
  1043.                 <!-- adjust value + or - -->
  1044.                 <xsl:choose>
  1045.                     <xsl:when test="contains($local-offset,'-')"><xsl:value-of select="0 - $offset-val"/></xsl:when>
  1046.                     <xsl:otherwise><xsl:value-of select="$offset-val"/></xsl:otherwise>
  1047.                 </xsl:choose>
  1048.             </xsl:otherwise>
  1049.         </xsl:choose>    
  1050.     </xsl:variable>
  1051.     <xsl:choose>
  1052.         <xsl:when test="$offset != 0">
  1053.             <xsl:variable name="dt2" select="translate($datetime,'-T:','')"/>
  1054.             <xsl:variable name="date-value">
  1055.                 <xsl:call-template name="date-time-to-float">
  1056.                     <xsl:with-param name="datetime" select="$dt2"/>
  1057.                 </xsl:call-template>
  1058.             </xsl:variable>
  1059.             <xsl:variable name="output-datetime">
  1060.                 <xsl:call-template name="float-to-date-time">
  1061.                     <xsl:with-param name="value" select="$date-value + $offset"/>
  1062.                     <xsl:with-param name="round-seconds" select="true()"/>
  1063.                 </xsl:call-template>
  1064.             </xsl:variable>
  1065.             <xsl:variable name="plusminus">
  1066.                 <xsl:choose>
  1067.                     <xsl:when test="contains($local-offset,'-')">-</xsl:when>
  1068.                     <xsl:otherwise>+</xsl:otherwise>
  1069.                 </xsl:choose>
  1070.             </xsl:variable>
  1071.             <!-- if seconds specified on the original time then add these back on -->
  1072.             <xsl:choose>
  1073.                 <xsl:when test="string-length($dt2) > 12"><xsl:value-of select="concat($output-datetime,':',substring($dt2,13,2),'Z',$plusminus,substring($raw-offset,1,2),':',substring($raw-offset,3,2))"/></xsl:when>
  1074.                 <xsl:otherwise><xsl:value-of select="concat($output-datetime,'Z',$plusminus,substring($raw-offset,1,2),':',substring($raw-offset,3,2))"/></xsl:otherwise>
  1075.             </xsl:choose>
  1076.         </xsl:when>
  1077.         <xsl:otherwise><xsl:value-of select="concat($datetime,'Z')"/></xsl:otherwise>
  1078.     </xsl:choose>
  1079. </xsl:template>
  1080.  
  1081. <!--
  1082. ==========================================================================
  1083.     Template: local-to-local
  1084.  Description: Converts one local date/time (in the format yyyymmddThhmmssZ+-hhmm
  1085.               or yyyy-mm-ddThh:mm:ssZ+-hh:mm) to another local date/time based
  1086.               upon a given new local time offset.
  1087.  Parameters:-
  1088.    <datetime>     the local date/time to be converted.
  1089.    <local-offset> the new local time offset (in the format +hh:mm or
  1090.                   -hh:mm)
  1091. -->
  1092. <xsl:template name="local-to-local">
  1093.     <xsl:param name="datetime"/>
  1094.     <xsl:param name="local-offset" select="'0000'"/>
  1095.     <!-- get the time zone offset part of the date/time -->
  1096.     <xsl:variable name="offset">
  1097.         <xsl:choose>
  1098.             <xsl:when test="contains($datetime,'Z')">
  1099.                 <!-- get the local offset portion (and strip out '+' and ':' chars) -->
  1100.                 <xsl:variable name="offset-portion" select="translate(substring-after($datetime,'Z'),'+:','')"/>
  1101.                 <xsl:choose>
  1102.                     <xsl:when test="string-length($offset-portion) = 0">0</xsl:when>
  1103.                     <xsl:otherwise>
  1104.                         <!-- convert hours/mins to a numeric value -->
  1105.                         <xsl:variable name="offset-val">
  1106.                             <xsl:call-template name="time-to-float">
  1107.                                 <xsl:with-param name="time" select="translate($offset-portion,'-','')"/>
  1108.                             </xsl:call-template>
  1109.                         </xsl:variable>
  1110.                         <!-- adjust value + or - -->
  1111.                         <xsl:choose>
  1112.                             <xsl:when test="substring($offset-portion,1,1) = '-'"><xsl:value-of select="0 - $offset-val"/></xsl:when>
  1113.                             <xsl:otherwise><xsl:value-of select="$offset-val"/></xsl:otherwise>
  1114.                         </xsl:choose>
  1115.                     </xsl:otherwise>
  1116.                 </xsl:choose>
  1117.             </xsl:when>
  1118.             <xsl:otherwise>0</xsl:otherwise>
  1119.         </xsl:choose>
  1120.     </xsl:variable>
  1121.     <!-- calc the new offset -->
  1122.     <xsl:variable name="raw-offset" select="concat(substring('0000',1,4 - string-length(translate($local-offset,'+-:',''))),translate($local-offset,'+-:',''))"/>
  1123.     <xsl:variable name="new-offset">
  1124.         <xsl:choose>
  1125.             <xsl:when test="$raw-offset = '0000'">0</xsl:when>
  1126.             <xsl:otherwise>
  1127.                 <!-- convert hours/mins to a numeric value -->
  1128.                 <xsl:variable name="offset-val">
  1129.                     <xsl:call-template name="time-to-float">
  1130.                         <xsl:with-param name="time" select="$raw-offset"/>
  1131.                     </xsl:call-template>
  1132.                 </xsl:variable>
  1133.                 <!-- adjust value + or - -->
  1134.                 <xsl:choose>
  1135.                     <xsl:when test="contains($local-offset,'-')"><xsl:value-of select="0 - $offset-val"/></xsl:when>
  1136.                     <xsl:otherwise><xsl:value-of select="$offset-val"/></xsl:otherwise>
  1137.                 </xsl:choose>
  1138.             </xsl:otherwise>
  1139.         </xsl:choose>
  1140.     </xsl:variable>
  1141.     <!-- perform the final time differential -->
  1142.     <xsl:choose>
  1143.         <xsl:when test="($offset != 0) and ($new-offset != 0)">
  1144.             <xsl:variable name="diff-offset" select="$new-offset - $offset"/>
  1145.             <xsl:variable name="dt2" select="translate(substring-before($datetime,'Z'),'-T:','')"/>
  1146.             <xsl:variable name="date-value">
  1147.                 <xsl:call-template name="date-time-to-float">
  1148.                     <xsl:with-param name="datetime" select="$dt2"/>
  1149.                 </xsl:call-template>
  1150.             </xsl:variable>
  1151.             <xsl:variable name="output-datetime">
  1152.                 <xsl:call-template name="float-to-date-time">
  1153.                     <xsl:with-param name="value" select="$date-value + $diff-offset"/>
  1154.                     <xsl:with-param name="round-seconds" select="true()"/>
  1155.                 </xsl:call-template>
  1156.             </xsl:variable>
  1157.             <xsl:variable name="plusminus">
  1158.                 <xsl:choose>
  1159.                     <xsl:when test="contains($local-offset,'-')">-</xsl:when>
  1160.                     <xsl:otherwise>+</xsl:otherwise>
  1161.                 </xsl:choose>
  1162.             </xsl:variable>
  1163.             <!-- if seconds specified on the original time then add these back on -->
  1164.             <xsl:choose>
  1165.                 <xsl:when test="string-length($dt2) > 12"><xsl:value-of select="concat($output-datetime,':',substring($dt2,13,2),'Z',$plusminus,substring($raw-offset,1,2),':',substring($raw-offset,3,2))"/></xsl:when>
  1166.                 <xsl:otherwise><xsl:value-of select="concat($output-datetime,'Z',$plusminus,substring($raw-offset,1,2),':',substring($raw-offset,3,2))"/></xsl:otherwise>
  1167.             </xsl:choose>
  1168.         </xsl:when>
  1169.         <xsl:otherwise><xsl:value-of select="concat($datetime,'Z')"/></xsl:otherwise>
  1170.     </xsl:choose>
  1171. </xsl:template>
  1172.  
  1173. </xsl:stylesheet>